package parser;

import com.github.javaparser.ParseException;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaParameter;
import com.thoughtworks.qdox.model.JavaType;
import entity.VariableEntity;
import type.ContainerTypeEnum;
import type.VariableTypeEnum;
import utils.ParserUtil;

public class VariableParser {

    public static VariableEntity createVariableEntity(JavaParameter jp) throws ParseException {
        if (jp != null) {
            VariableEntity entity = new VariableEntity();
            entity.setName(jp.getName());
            entity.setCode(jp.getCodeBlock());
            entity.setFinal(jp.getJavaClass().isFinal());
            entity.setVariableTypeEnum(getVariableType(jp.getJavaClass()));
            entity.setOriginClass(ClassParser.createClassEntity(jp.getJavaClass()));
            // 是容器？
            entity.setContainerType(getContainerType(jp.getJavaClass(), entity.getVariableTypeEnum()));
            // 容器元素
            entity.setContainerItems(getContainerItems(jp.getJavaClass(), entity.getContainerType()));
            return entity;
        }

        return null;
    }

    public static VariableEntity createVariableEntity(JavaClass cls) throws ParseException {
        if (cls != null) {
            VariableEntity entity = new VariableEntity();
            entity.setVariableTypeEnum(getVariableType(cls));
            entity.setOriginClass(ClassParser.createClassEntity(cls));
            // 是容器？
            entity.setContainerType(getContainerType(cls, entity.getVariableTypeEnum()));
            // 容器元素
            entity.setContainerItems(getContainerItems(cls, entity.getContainerType()));
            return entity;
        }

        return null;
    }

    public static VariableEntity createVariableEntity(String fullyQualifiedName) throws ParseException {
        return createVariableEntity(ParserUtil.getJavaClassByName(fullyQualifiedName));
    }

    /**
     * 获取变量分类
     */
    public static VariableTypeEnum getVariableType(JavaClass jf) {
        if (isGeneric(jf)) {
            return VariableTypeEnum.TYPE_PARAMETER;
        } else if (jf.isPrimitive()) {
            return VariableTypeEnum.PRIMITIVE;
        } else {
            return VariableTypeEnum.REFERENCE;
        }
    }

    /**
     * 判断是类型变量，与类型变量声明列表匹配
     */
    public static boolean isGeneric(JavaClass jf) {
        for (JavaType jt : jf.getDeclaringClass().getTypeParameters()) {
            if (jf.getGenericFullyQualifiedName().equals(jt.getGenericFullyQualifiedName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 提取容器元素类型
     */
    public static VariableEntity[] getContainerItems(JavaClass jf, ContainerTypeEnum type) throws ParseException {
        VariableEntity[] containerItems = new VariableEntity[2];
        if (type == ContainerTypeEnum.ARRAY) {
            containerItems[0] = VariableParser.createVariableEntity(jf.getComponentType());
            return containerItems;
        }
        if (type == ContainerTypeEnum.COLLECTION || type == ContainerTypeEnum.CUSTOM) {
            String str = jf.getGenericFullyQualifiedName();
            containerItems[0] = VariableParser.createVariableEntity(str.substring(str.indexOf('<') + 1, str.lastIndexOf('>')));
            return containerItems;
        }
        if (type == ContainerTypeEnum.MAP) {
            String str = jf.getGenericFullyQualifiedName();
            str = str.substring(str.indexOf('<') + 1, str.lastIndexOf('>'));
            String[] tmp = str.split(",");
            containerItems[0] = VariableParser.createVariableEntity(tmp[0]);
            containerItems[1] = VariableParser.createVariableEntity(tmp[1]);
            return containerItems;
        }
        return null;
    }

    /**
     * 判断是容器
     * 容器（可存储相同类型元素）包括：
     * 1. 单列集合：实现 java.util.Collection 接口
     * 2. 双列集合：实现 java.util.Map 接口
     * 3. 自定义容器：实现 java.util.Iterator 或 java.util.Enumeration 接口
     * 4. 数组
     * 3 的例子：NetworkInterface.getNetworkInterfaces() 返回 Enumeration<NetworkInterface>
     */
    public static ContainerTypeEnum getContainerType(JavaClass jf, VariableTypeEnum type) {
        if (jf.isArray()) {
            return ContainerTypeEnum.ARRAY;
        }
        if (type != VariableTypeEnum.REFERENCE) {
            return ContainerTypeEnum.NOT;
        }
        if (jf.isA("java.util.Collection")) {
            return ContainerTypeEnum.COLLECTION;
        }
        if (jf.isA("java.util.Map")) {
            return ContainerTypeEnum.MAP;
        }
        if (jf.isA("java.util.Enumeration") ||
                jf.isA("java.util.Iterator")) {
            return ContainerTypeEnum.CUSTOM;
        }
        return ContainerTypeEnum.NOT;
    }
}
